from typing import Iterable


def write_uint(value: int, size: int) -> bytes:
    if value < 0 or value >= (1 << (size * 8)):
        raise ValueError(f"value {value} out of range for {size} bytes")
    return value.to_bytes(size, byteorder='big')


def encode_bcd(number_str: str, fixed_len: int) -> bytes:
    # Pads left with '0' to reach fixed number of digits
    digits = ''.join(ch for ch in number_str if ch.isdigit())
    if len(digits) > fixed_len:
        raise ValueError('BCD input longer than fixed length')
    digits = digits.rjust(fixed_len, '0')
    # Pair digits
    out = bytearray()
    for i in range(0, fixed_len, 2):
        high = int(digits[i])
        low = int(digits[i + 1])
        out.append((high << 4) | low)
    return bytes(out)


def encode_bcd_from_ints(int_list):
    # helper: encode list of two-digit components into BCD bytes
    out = bytearray()
    for val in int_list:
        out.append(((val // 10) << 4) | (val % 10))
    return bytes(out)


def xor_checksum(data: bytes) -> int:
    cs = 0
    for b in data:
        cs ^= b
    return cs & 0xFF


def escape_bytes(data: bytes) -> bytes:
    out = bytearray()
    for b in data:
        if b == 0x7d:
            out.extend([0x7d, 0x01])
        elif b == 0x7e:
            out.extend([0x7d, 0x02])
        else:
            out.append(b)
    return bytes(out)


def to_hex(data: bytes) -> str:
    return data.hex()

def from_hex(hex_str: str) -> bytes:
    # 清理所有空白字符：空格、制表符、换行符、回车符等
    import re
    hex_str = re.sub(r'\s+', '', hex_str.strip())
    if hex_str.startswith('0x') or hex_str.startswith('0X'):
        hex_str = hex_str[2:]
    if len(hex_str) % 2 != 0:
        raise ValueError('十六进制字符串长度必须为偶数')
    try:
        return bytes.fromhex(hex_str)
    except Exception as e:
        raise ValueError(f'from_hex 解析失败: {e}')
        

def unescape_bytes(data: bytes) -> bytes:
    out = bytearray()
    i = 0
    while i < len(data):
        b = data[i]
        if b == 0x7d and i + 1 < len(data):
            nxt = data[i + 1]
            if nxt == 0x01:
                out.append(0x7d)
                i += 2
                continue
            if nxt == 0x02:
                out.append(0x7e)
                i += 2
                continue
        out.append(b)
        i += 1
    return bytes(out)


